package com.even.camerarecoder.aac

import android.os.Environment
import android.text.format.DateFormat
import com.even.camerarecoder.App
import com.even.camerarecoder.MediaUtil
import com.even.camerarecoder.SDCardUtil
import com.evendai.loglibrary.Timber
import java.io.File
import java.io.FileOutputStream
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.util.concurrent.Executors

class AACSaver {

    private val deleteThreadPool = Executors.newFixedThreadPool(1)
    private lateinit var outputStream: FileOutputStream
    private lateinit var outputChannel: FileChannel
    private var createOutputStreamOk: Boolean = false
    /** 开始保存AAC的时间，从这个时间开始算，10分钟后保存这个AAC文件再创建新文件保存   */
    private var recordAudioStartTime = 0L
    private var mFrameCount = 0L
    /** 10分钟   */
//    private val tenMinutes = 1000L * 60 * 10
    private val tenMinutes = 1000L * 60 * 1
    /** SDCard路径 */
    private var mSdCardPath: String? = null
    /** 视频保存目录 */
    private lateinit var mAudioSaveDir: File
    /** 指示是否有SDCard  */
    private var hasSDCard = false
    private var mAudioFile: File? = null
    @Suppress("PrivatePropertyName")
    private val _1K: Long = 1024L
    @Suppress("PrivatePropertyName")
    private val _1M: Long = 1024L * _1K
    @Suppress("PrivatePropertyName")
    private val _200M: Long = 200L * _1M
    /** 表示已经调用了close()方法 */
    private var calledCloseMethod = false

    init {
        checkHasSDCard()

        if (hasSDCard) {
            /*// 不没有系统权限时，则使用下面的目录来存储视频，此目录不需要任何存储权限
            val movieDirs = NgnApplication.getContext().getExternalFilesDirs(Environment.DIRECTORY_MUSIC)
            mAudioSaveDir = if (movieDirs.isNullOrEmpty() || movieDirs.size < 2) {
                File(mSdCardPath, "/Android/data/${NgnApplication.getContext().packageName}/files/Audio")
            } else {
                movieDirs[0] // 数组中的第一个条目被视为主要外部存储，即不可移除的。第二个则为SDCard，可移除的
            }*/

            /*mAudioSaveDir = File(mSdCardPath, "/DCIM/Audio")

            if (!mAudioSaveDir.exists()) {
                if (!mAudioSaveDir.mkdirs()) {
                    Timber.e("创建音频保存目录失败!")
                    hasSDCard = false
                }
            }*/

            mAudioSaveDir = App.sContext.getExternalFilesDir(Environment.DIRECTORY_MUSIC)!!

            // 第一次在外置SDCard创建文件时花的时间比较长，第二次创建就快了，所以这里先创建一次，方便第二次创建时提速
            if (hasSDCard) {
                val testFile = File(mAudioSaveDir, "test.aac")
                if (!testFile.exists()) {
                    if (testFile.createNewFile()) {
                        testFile.delete()
                    }
                } else {
                    testFile.delete()
                }
            }
        } else {
            Timber.fe("没有检测到SDCard")
        }

    }

    private fun checkHasSDCard() {
        mSdCardPath = Environment.getExternalStorageDirectory().absolutePath
        hasSDCard = mSdCardPath != null
    }

    @Synchronized
    fun close() {
        if (calledCloseMethod) return
        calledCloseMethod = true
        saveAACFile()
    }

    /** 把aac写到文件中，此函数执行非常快，平均0.2 ~ 0.4毫秒 */
    @Synchronized
    fun saveAAC(aacByteBuffer: ByteBuffer) {
        if (!hasSDCard || calledCloseMethod) return // calledCloseMethod用于预防多线程时一个线程调用了close()，一个线程又正好又调用了saveAAC(ByteBuffer)

        if (!createOutputStreamOk) {
            createAACFile()
            if (!createOutputStreamOk) return
        }

        try {
            if (recordAudioStartTime == 0L) {
                recordAudioStartTime = System.currentTimeMillis() // 记录刚开始保存视频时的时间
            }
            val recordAACElapsedTime = System.currentTimeMillis() - recordAudioStartTime
            if (recordAACElapsedTime >= tenMinutes) {
                Timber.i("录制的音频大于了10分钟")
                saveAACFile()
                createAACFile()
                if (!createOutputStreamOk) return
            }

            outputChannel.write(aacByteBuffer)
            mFrameCount++
        } catch (e: Exception) {
            Timber.e(e,"写aac数据时出现异常")
            checkHasSDCard()
            saveAACFile()
        }
    }

    private fun createAACFile() {
        // 确保有足够的空间存储文件
        if (!hasSDCard) return
        ensureEnoughSpace()
        val fileName = "${DateFormat.format("yyyy_MM_dd_kk_mm_ss", System.currentTimeMillis())}.aac"
        mAudioFile = File(mAudioSaveDir, fileName)
        recordAudioStartTime = 0
        mFrameCount = 0

        try {
            outputStream = FileOutputStream(mAudioFile!!)
            outputChannel = outputStream.channel
            createOutputStreamOk = true
        } catch (e: Exception) {
            checkHasSDCard()
            createOutputStreamOk = false
            Timber.fw(e,"创建AAC文件失败：${mAudioFile!!.absolutePath}")
            if (mAudioFile != null && mAudioFile!!.exists()) {
                val isDelete = mAudioFile!!.delete()
                Timber.e("生成了一个空文件，是否删除成功：$isDelete, 文件名为：${mAudioFile!!.absolutePath}")
                mAudioFile = null
            }
        }
    }

    /** 确保有足够的可用空间 */
    private fun ensureEnoughSpace() {
        while (SDCardUtil.getSdCardUsableSpace(mSdCardPath) < _200M) {
            deleteThreadPool.execute {
                while (SDCardUtil.getSdCardUsableSpace(mSdCardPath) < _200M) {
                    deleteOldestFile()
                }
            }
        }
    }

    private fun deleteOldestFile() {
        if (!mAudioSaveDir.exists()) return
        val listFiles = mAudioSaveDir.listFiles()
        if (listFiles.isNullOrEmpty()) return
        val oldestFile = listFiles.minByOrNull { it.lastModified() }!! // 修改时间最小的就是最老的
        val delete = oldestFile.delete()
        Timber.i("空间小于200M，删除最老的文件：${oldestFile.absolutePath},是否删除成功：$delete")
    }

    private fun saveAACFile() {
        if (!hasSDCard) return

        closeIO()

        if (mAudioFile?.exists() == true){
            val durationString = MediaUtil.getMediaDuration(mAudioFile!!.absolutePath) ?: "-1"
            var duration = 0
            try {
                duration = durationString.toInt()
            } catch (e: Exception) {
                Timber.e("文件时长转换为int时出现异常，durationString = $durationString")
            }

            if (duration < 3000) { // 小于3秒钟的视频不保存，直接删掉
                val delete = mAudioFile!!.delete()
                Timber.i("删除了一个小于10K的文件，是否删除成功：$delete,它的名字为：${mAudioFile!!.absolutePath}")
            } else {
                Timber.i("保存了一个音频文件，，路径：${mAudioFile!!.absolutePath}")
            }
        }

        recordAudioStartTime = 0
        mFrameCount = 0
        mAudioFile = null
    }

    private fun closeIO() {
        if (!createOutputStreamOk) {
            return
        }

        createOutputStreamOk = false
        try {
            outputChannel.close()
        } catch (e: Exception) {
            Timber.fe(e,"别慌，正常关闭outputChannel时出现异常")
        }
        try {
            outputStream.close()
        } catch (e: Exception) {
            Timber.fe(e,"别慌，正常关闭outputStream时出现异常")
        }
    }
}